#include "OpenGLSupport.h"

#include "../../HObject.h"
#include "OpenGLExt.h"

//multitexture extensions
PFNGLMULTITEXCOORD1FARBPROC glMultiTexCoord1fARB = NULL;
PFNGLMULTITEXCOORD1FVARBPROC glMultiTexCoord1fvARB = NULL;
PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB = NULL;
PFNGLMULTITEXCOORD2FVARBPROC glMultiTexCoord2fvARB = NULL; 
PFNGLMULTITEXCOORD3FARBPROC glMultiTexCoord3fARB = NULL;
PFNGLMULTITEXCOORD3FVARBPROC glMultiTexCoord3fvARB = NULL;
PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = NULL;
PFNGLCLIENTACTIVETEXTUREARBPROC	glClientActiveTextureARB = NULL;
//vsync extensions
PFNWGLEXTSWAPINTERVALPROC wglSwapIntervalEXT = NULL;
PFNWGLEXTGETSWAPINTERVALPROC wglGetSwapIntervalEXT = NULL;
//draw range elements extension
PFNGLDRAWRANGEELEMENTSEXTPROC glDrawRangeElementsEXT = NULL;
//GLSL extensions
PFNGLVERTEXATTRIB1FARBPROC glVertexAttrib1fARB = NULL;
PFNGLVERTEXATTRIB1FVARBPROC glVertexAttrib1fvARB = NULL;
PFNGLVERTEXATTRIB2FARBPROC glVertexAttrib2fARB = NULL;
PFNGLVERTEXATTRIB2FVARBPROC glVertexAttrib2fvARB = NULL;
PFNGLVERTEXATTRIB3FARBPROC glVertexAttrib3fARB = NULL;
PFNGLVERTEXATTRIB3FVARBPROC glVertexAttrib3fvARB = NULL;
PFNGLVERTEXATTRIB4FARBPROC glVertexAttrib4fARB = NULL;
PFNGLVERTEXATTRIB4FVARBPROC glVertexAttrib4fvARB = NULL;
PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB = NULL;
PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB = NULL;
PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB = NULL;
PFNGLPROGRAMSTRINGARBPROC glProgramStringARB = NULL;
PFNGLBINDPROGRAMARBPROC glBindProgramARB = NULL;
PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB = NULL;
PFNGLGENPROGRAMSARBPROC glGenProgransARB = NULL;
PFNGLPROGRAMENVPARAMETER4FARBPROC glProgramEnvParameter4fARB = NULL;
PFNGLPROGRAMENVPARAMETER4FVARBPROC glProgramEnvParameter4fvARB = NULL;
PFNGLPROGRAMLOCALPARAMETER4FARBPROC glProgramLocalParameter4fARB = NULL;
PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB = NULL;
PFNGLGETPROGRAMENVPARAMETERFVARBPROC glGetProgramEnvParameterfvARB = NULL;
PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glGetProgramLocalParameterfvARB = NULL;
PFNGLGETPROGRAMIVARBPROC glGetProgramivARB = NULL;
PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB = NULL;
PFNGLGETVERTEXATTRIBFVARBPROC glGetVertexAttribfvARB = NULL;
PFNGLGETVERTEXATTRIBPOINTERVARBPROC glGetVertexAttribPointervARB = NULL;
PFNGLISPROGRAMARBPROC glIsProgramARB = NULL;

//Functions to create GLSL shaders and programs
PFNGLDELETEOBJECTARBPROC glDeleteObjectARB = NULL;
PFNGLGETHANDLEARBPROC glGetHandleARB = NULL;
PFNGLDETACHOBJECTARBPROC glDetachObjectARB = NULL;
PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB = NULL;
PFNGLSHADERSOURCEARBPROC glShaderSourceARB = NULL;
PFNGLCOMPILESHADERARBPROC glCompileShaderARB = NULL;
PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB = NULL;
PFNGLATTACHOBJECTARBPROC glAttachObjectARB = NULL;
PFNGLLINKPROGRAMARBPROC glLinkProgramARB = NULL;
PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB = NULL;
PFNGLVALIDATEPROGRAMARBPROC glValidateProgranARB = NULL;

//Functions for setting float uniform values
PFNGLUNIFORM1FARBPROC glUniform1fARB = NULL;
PFNGLUNIFORM1FVARBPROC glUniform1fvARB = NULL;
PFNGLUNIFORM2FARBPROC glUniform2fARB = NULL;
PFNGLUNIFORM2FVARBPROC glUniform2fvARB = NULL;
PFNGLUNIFORM3FARBPROC glUniform3fARB = NULL;
PFNGLUNIFORM3FVARBPROC glUniform3fvARB = NULL;
PFNGLUNIFORM4FARBPROC glUniform4fARB = NULL;
PFNGLUNIFORM4FVARBPROC glUniform4fvARB = NULL;
PFNGLUNIFORMMATRIX2FVARBPROC glUniformMatrix2fvARB = NULL;
PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB = NULL;
PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB = NULL;

//Functions for setting int uniform values
//Uniform int variable functions
PFNGLUNIFORM1IARBPROC glUniform1iARB = NULL;
PFNGLUNIFORM1IVARBPROC glUniform1ivARB = NULL;
PFNGLUNIFORM2IARBPROC glUniform2iARB = NULL;
PFNGLUNIFORM2IVARBPROC glUniform2ivARB = NULL;
PFNGLUNIFORM3IARBPROC glUniform3iARB = NULL;
PFNGLUNIFORM3IVARBPROC glUniform3ivARB = NULL;
PFNGLUNIFORM4IARBPROC glUniform4iARB = NULL;
PFNGLUNIFORM4IVARBPROC glUniform4ivARB = NULL;

PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB = NULL;
PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB = NULL;
PFNGLGETINFOLOGARBPROC glGetInfoLogARB = NULL;
PFNGLGETATTACHEDOBJECTSARBPROC glGetAttachedObjectsARB = NULL;
PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB = NULL;
PFNGLGETACTIVEUNIFORMARBPROC glGetActiveUniformARB = NULL;
PFNGLGETUNIFORMFVARBPROC glGetUniformfvARB = NULL;
PFNGLGETUNIFORMIVARBPROC glGetUniformivARB = NULL;
PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB = NULL;
PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB = NULL;
PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB = NULL;
PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB = NULL;



namespace helix
{


	OpenGLExtensions::OpenGLExtensions()
	{
		extensions=0;
		ExtStr=(const char*)glGetString (GL_EXTENSIONS);

		Log().Print("Initializing OpenGL Extensions...\nSupported Extensions:\n    ");
		unsigned int i=0;
		while(i<strlen(ExtStr))
		{
			Log().Print("%c",ExtStr[i]);
			if(ExtStr[i]==' ')
			{
				extensions++;
				Log().Print("\n    ");
			}

			i++;
		}
		Log().Println("");

		//see if these extensions are supported and if they are, let's use them

	/*************MULTITEXTURE EXTENSIONS (8 TOTAL)**************/
		if(ExtSupported[H_MULTI_TEX_SUPPORT]=(strstr((const char *)ExtStr, "GL_ARB_multitexture")!=NULL))
		{
			//There are a lot more functions, but we will only be using floats, so we don't need them
			glMultiTexCoord1fARB=(PFNGLMULTITEXCOORD1FARBPROC) wglGetProcAddress("glMultiTexCoord1fARB");
			glMultiTexCoord1fvARB=(PFNGLMULTITEXCOORD1FVARBPROC) wglGetProcAddress("glMultiTexCoord1fvARB");
			glMultiTexCoord2fARB=(PFNGLMULTITEXCOORD2FARBPROC) wglGetProcAddress("glMultiTexCoord2fARB");
			glMultiTexCoord2fvARB=(PFNGLMULTITEXCOORD2FVARBPROC) wglGetProcAddress("glMultiTexCoord2fvARB");
			glMultiTexCoord3fARB=(PFNGLMULTITEXCOORD3FARBPROC) wglGetProcAddress("glMultiTexCoord3fARB");
			glMultiTexCoord3fvARB=(PFNGLMULTITEXCOORD3FVARBPROC) wglGetProcAddress("glMultiTexCoord3fvARB");
			glActiveTextureARB= (PFNGLACTIVETEXTUREARBPROC) wglGetProcAddress("glActiveTextureARB");
			glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC) wglGetProcAddress("glClientActiveTextureARB");
		}

	/*************VSYNC EXTENSIONS*********************/
		if(ExtSupported[H_SWAP_CONTROL]=(strstr((const char*)ExtStr,"WGL_EXT_swap_control")!=NULL))
		{
			wglSwapIntervalEXT = (PFNWGLEXTSWAPINTERVALPROC) wglGetProcAddress("wglSwapIntervalEXT");
			wglGetSwapIntervalEXT = (PFNWGLEXTGETSWAPINTERVALPROC) wglGetProcAddress("wglGetSwapIntervalExt");
		}

	/************DRAW RANGE ELEMENTS EXTENSION****************/
		if(ExtSupported[H_DRAW_RANGE_ELEMENTS]=(strstr((const char*)ExtStr,"GL_EXT_draw_range_elements")!=NULL))
			glDrawRangeElementsEXT = (PFNGLDRAWRANGEELEMENTSEXTPROC) wglGetProcAddress("glDrawRangeElementsEXT");

	/*************GLSL EXTENSIONS****************/
		if(ExtSupported[H_GLSL]=((strstr((const char*)ExtStr,"GL_ARB_vertex_shader")!=NULL) && 
								(strstr((const char*)ExtStr,"GL_ARB_fragment_shader")!=NULL)))
		{
			//There are a lot more functions, but we will only be using floats and ints, so we don't need all of them
			glVertexAttrib1fARB = (PFNGLVERTEXATTRIB1FARBPROC) wglGetProcAddress("glVertexAttrib1fARB");
			glVertexAttrib1fvARB = (PFNGLVERTEXATTRIB1FVARBPROC) wglGetProcAddress("glVertexAttrib1fvARB");
			glVertexAttrib2fARB = (PFNGLVERTEXATTRIB2FARBPROC) wglGetProcAddress("glVertexAttrib2fARB");
			glVertexAttrib2fvARB = (PFNGLVERTEXATTRIB2FVARBPROC) wglGetProcAddress("glVertexAttrib2fvARB");
			glVertexAttrib3fARB = (PFNGLVERTEXATTRIB3FARBPROC) wglGetProcAddress("glVertexAttrib3fARB");
			glVertexAttrib3fvARB = (PFNGLVERTEXATTRIB3FVARBPROC) wglGetProcAddress("glVertexAttrib3fvARB");
			glVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC) wglGetProcAddress("glVertexAttrib4fARB");
			glVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC) wglGetProcAddress("glVertexAttrib4fvARB");
			glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC) wglGetProcAddress("glVertexAttribPointerARB");
			glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC) wglGetProcAddress("glEnableVertexAttribArrayARB");
			glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) wglGetProcAddress("glDisableVertexAttribArrayARB");
			glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) wglGetProcAddress("glProgramStringARB");
			glBindProgramARB = (PFNGLBINDPROGRAMARBPROC) wglGetProcAddress("glBindProgramARB");
			glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) wglGetProcAddress("glDeleteProgramsARB");
			glGenProgransARB = (PFNGLGENPROGRAMSARBPROC) wglGetProcAddress("glGenProgransARB");
			glProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC) wglGetProcAddress("glProgramEnvParameter4fARB");
			glProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC) wglGetProcAddress("glProgramEnvParameter4fvARB");
			glProgramLocalParameter4fARB =(PFNGLPROGRAMLOCALPARAMETER4FARBPROC) wglGetProcAddress("glProgramLocalParameter4fARB");
			glProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) wglGetProcAddress("glProgramLocalParameter4fvARB");
			glGetProgramEnvParameterfvARB = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC) wglGetProcAddress("glGetProgramEnvParameterfvARB");
			glGetProgramLocalParameterfvARB = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) wglGetProcAddress("glGetProgramLocalParameterfvARB");
			glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC) wglGetProcAddress("glGetProgramivARB");
			glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC) wglGetProcAddress("glGetProgramStringARB");
			glGetVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC) wglGetProcAddress("glGetVertexAttribfvARB");
			glGetVertexAttribPointervARB = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC) wglGetProcAddress("glGetVertexAttribPointervARB");
			glIsProgramARB = (PFNGLISPROGRAMARBPROC) wglGetProcAddress("glIsProgramARB");

			//Functions for creating GLSL shaders and programs
			glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) wglGetProcAddress("glDeleteObjectARB");
			glGetHandleARB = (PFNGLGETHANDLEARBPROC) wglGetProcAddress("glGetHandleARB");
			glDetachObjectARB = (PFNGLDETACHOBJECTARBPROC) wglGetProcAddress("glDetachObjectARB");
			glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) wglGetProcAddress("glCreateShaderObjectARB");
			glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) wglGetProcAddress("glShaderSourceARB");
			glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) wglGetProcAddress("glCompileShaderARB");
			glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) wglGetProcAddress("glCreateProgramObjectARB");
			glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) wglGetProcAddress("glAttachObjectARB");
			glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) wglGetProcAddress("glLinkProgramARB");
			glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) wglGetProcAddress("glUseProgramObjectARB");
			glValidateProgranARB = (PFNGLVALIDATEPROGRAMARBPROC) wglGetProcAddress("glValidateProgranARB");

			//Functions for setting uniform float variables
			glUniform1fARB = (PFNGLUNIFORM1FARBPROC) wglGetProcAddress("glUniform1fARB");
			glUniform1fvARB = (PFNGLUNIFORM1FVARBPROC) wglGetProcAddress("glUniform1fvARB");
			glUniform2fARB = (PFNGLUNIFORM2FARBPROC) wglGetProcAddress("glUniform2fARB");
			glUniform2fvARB = (PFNGLUNIFORM2FVARBPROC) wglGetProcAddress("glUniform2fvARB");
			glUniform3fARB = (PFNGLUNIFORM3FARBPROC) wglGetProcAddress("glUniform3fARB");
			glUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) wglGetProcAddress("glUniform3fvARB");
			glUniform4fARB = (PFNGLUNIFORM4FARBPROC) wglGetProcAddress("glUniform4fARB");
			glUniform4fvARB = (PFNGLUNIFORM4FVARBPROC) wglGetProcAddress("glUniform4fvARB");
			glUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC) wglGetProcAddress("glUniformMatrix2fvARB");
			glUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC) wglGetProcAddress("glUniformMatrix3fvARB");
			glUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC) wglGetProcAddress("glUniformMatrix4fvARB");

			//Functions for setting uniform int variables
			glUniform1iARB = (PFNGLUNIFORM1IARBPROC) wglGetProcAddress("glUniform1iARB");
			glUniform1ivARB = (PFNGLUNIFORM1IVARBPROC) wglGetProcAddress("glUniform1ivARB");
			glUniform2iARB = (PFNGLUNIFORM2IARBPROC) wglGetProcAddress("glUniform2iARB");
			glUniform2ivARB = (PFNGLUNIFORM2IVARBPROC) wglGetProcAddress("glUniform2ivARB");
			glUniform3iARB = (PFNGLUNIFORM3IARBPROC) wglGetProcAddress("glUniform3iARB");
			glUniform3ivARB = (PFNGLUNIFORM3IVARBPROC) wglGetProcAddress("glUniform3ivARB");
			glUniform4iARB = (PFNGLUNIFORM4IARBPROC) wglGetProcAddress("glUniform4iARB");
			glUniform4ivARB = (PFNGLUNIFORM4IVARBPROC) wglGetProcAddress("glUniform4ivARB");

			glGetObjectParameterfvARB = (PFNGLGETOBJECTPARAMETERFVARBPROC) wglGetProcAddress("glGetObjectParameterfvARB");
			glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) wglGetProcAddress("glGetObjectParameterivARB");
			glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) wglGetProcAddress("glGetInfoLogARB");
			glGetAttachedObjectsARB = (PFNGLGETATTACHEDOBJECTSARBPROC) wglGetProcAddress("glGetAttachedObjectsARB");
			glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) wglGetProcAddress("glGetUniformLocationARB");
			glGetActiveUniformARB = (PFNGLGETACTIVEUNIFORMARBPROC) wglGetProcAddress("glGetActiveUniformARB");
			glGetUniformfvARB = (PFNGLGETUNIFORMFVARBPROC) wglGetProcAddress("glGetUniformfvARB");
			glGetUniformivARB = (PFNGLGETUNIFORMIVARBPROC) wglGetProcAddress("glGetUniformivARB");
			glGetShaderSourceARB = (PFNGLGETSHADERSOURCEARBPROC) wglGetProcAddress("glGetShaderSourceARB");
			glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC) wglGetProcAddress("glBindAttribLocationARB");
			glGetActiveAttribARB = (PFNGLGETACTIVEATTRIBARBPROC) wglGetProcAddress("glGetActiveAttribARB");
			glGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC) wglGetProcAddress("glGetAttribLocationARB");
		}
		

		extensions=0;
		for(int i=0;i<MAX_OPEN_GL_EXTENSIONS;i++)
		{
			if(ExtSupported[i])       //a quick check to see if all our extensions needed are supported
				extensions++;
		}
	}

	OpenGLExtensions::~OpenGLExtensions()
	{
	//	if (ExtStr!=NULL)
	//		delete []ExtStr;
	}

	bool OpenGLExtensions::Supported(int extension)
	{
		if(extension>=0 && extension<MAX_OPEN_GL_EXTENSIONS)
			return ExtSupported[extension];

		return false;
	}

	void OpenGLExtensions::Print()
	{
		Log().Println("# of supported extensions = %d",extensions);
		for(int i=0;i<MAX_OPEN_GL_EXTENSIONS;i++)
			Log().Print("%d=%d   ",i,ExtSupported[i]);

	}

} //end of helix namespace

